/**
 * AbstractRequester.java
 *
 * @author liujie11
 * 
 * @date 2013-4
 * 
 */
package com.baidu.common.async_http;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;

import com.baidu.common.net.HttpEngine;
import com.baidu.common.net.HttpRequestData;
import com.baidu.common.net.NetworkErrorException;
import com.baidu.common.net.NetworkTimeoutException;
import com.baidu.common.net.ServerErrorException;
import com.baidu.common.utils.AppLog;
import com.baidu.common.utils.Tools;
import com.japher.hackson.response.BaseResponse;

public abstract class AbstractRequester extends AsyncTaskEx<HttpRequestData, Integer, BaseResponse> {
    
    private static final int CORE_POOL_SIZE = 10;
    private static final int MAXIMUM_POOL_SIZE = 60;
    private static final int KEEP_ALIVE = 10;
    
    private static final BlockingQueue<Runnable> sWorkQueue = new LinkedBlockingQueue<Runnable>(10);
    
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
        
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
            t.setPriority(Thread.MAX_PRIORITY);
            return t;
        }
    };
    
    private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
        MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
    
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        if (progressListener != null && values != null) {
            progressListener.onProgress(values[0].intValue());
        }
    }
    
    @Override
    protected void onCancelled() {
        super.onCancelled();
        if (listener != null) {
            BaseResponse r = new BaseResponse();
            r.setStatus(BaseResponse.ERR_CODE_USER_CANCEL);
            listener.onRequestComplete(r);
        }
        listener = null;
    }
    
    /**
     * 判定当前任务是否正在运行
     * 
     * @return
     */
    public boolean isRunning() {
        if (getStatus() == AsyncTaskEx.Status.RUNNING || getStatus() == AsyncTaskEx.Status.PENDING) {
            return true;
        }
        return false;
    }
    
    /**
     * 强行中止当前任务
     * 
     * @return
     */
    public void breakHttpTask() {
        if (isRunning()) {
            cancel(true);
        }
    }
    
    /**
     * 根据自己的类型生成要发送的数据
     * 
     * @return
     */
    abstract protected HttpRequestData createSendData();
    
    /**
     * 根据自己的类型生成相应的parser
     * 
     * @return
     */
    abstract protected AbstractParser createParser();
    
    IResponseListener listener = null;
    IResponseProgressListener progressListener;
    
    public IResponseProgressListener getProgressListener() {
        return progressListener;
    }
    
    public void setProgressListener(IResponseProgressListener progressListener) {
        this.progressListener = progressListener;
    }
    
    public void setListener(IResponseListener listener) {
        this.listener = listener;
    }
    
    @Override
    protected void onPostExecute(BaseResponse result) {
        super.onPostExecute(result);
        if (listener != null) {
            listener.onRequestComplete(result);
        }
    }
    
    protected int length = -1;
    
    @Override
    protected BaseResponse doInBackground(HttpRequestData... arg0) {
        
        HttpEngine httpEngine = null;
        BaseResponse response = null;
        AbstractParser parser = createParser();
        httpEngine = HttpEngine.create();
        try {
            final HttpRequestData requestData = arg0[0];
            
            AppLog.debug("Request Url", requestData.getUrl());
            InputStream in = null;
            if (requestData.isGzip()) {
                try {
                    InputStream remote = httpEngine.executeHttpRequest(requestData);
                    in = new GZIPInputStream(remote);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                in = httpEngine.executeHttpRequest(requestData);
            }
            
            length = (int) httpEngine.getLength();
            response = parser.parse(in);
            publishProgress(100);
        }
        
        catch (NetworkTimeoutException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            response = new BaseResponse();
            response.setStatusMessage("网络请求超时");
            
        } catch (NetworkErrorException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            response = new BaseResponse();
            response.setStatus(BaseResponse.ERR_CODE_NET);
            response.setStatusMessage("网络错误");
            
        } catch (ServerErrorException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            response = new BaseResponse();
            if (!Tools.isEmpty(e.getErrordJson())) {
                response.setException(e);
            }
            response.setStatus(BaseResponse.ERR_CODE_SERVER);
            response.setStatusMessage("连接服务器错误");
        }
        
        return response;
    }
    
    public void StartRequest(IResponseListener aListener) {
        
        this.listener = aListener;
        HttpRequestData[] params = new HttpRequestData[1];
        params[0] = createSendData();
        try {
            if (params[0] != null)
                this.execute(params);
            // this.executeOnExecutor(exec, params);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    protected ThreadPoolExecutor getThreadPoolExecutor() {
        return sExecutor;
    }
}
